package cn.wuwenyao.patch.generator;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.wuwenyao.patch.generator.entity.GitProjectInfo;
import cn.wuwenyao.patch.generator.entity.PatchInfo;
import cn.wuwenyao.patch.generator.entity.ProjectInfo;
import cn.wuwenyao.patch.generator.enums.VersionManagerType;
import cn.wuwenyao.patch.generator.utils.ZipUtil;

/***
 * git 补丁生成器
 * 
 * @author wwy
 *
 */
public class GitPatchGenerator implements PatchGenerator {
	
	private static final Logger LOG = LoggerFactory.getLogger(GitPatchGenerator.class);
	
	@Override
	public boolean support(VersionManagerType manageType) {
		return manageType.equals(VersionManagerType.GIT);
	}
	
	@Override
	public void generatePatch(ProjectInfo projectInfo, PatchInfo patchInfo) throws Exception {
		if (projectInfo instanceof GitProjectInfo) {
			
		} else {
			throw new RuntimeException("ProjectInfo只支持GitProjectInfo实例");
		}
		GitProjectInfo gitProjectInfo = (GitProjectInfo) projectInfo;
		patchInfo.setPatchFileDir(
				patchInfo.getPatchFileDir() + "/" + DateFormatUtils.format(new Date(), "yyyy-MM-dd-hh-mm-ss"));
		Repository repository;
		repository = new RepositoryBuilder().setGitDir(new File(gitProjectInfo.getGitRepositoryUrl())).build();
		Set<String> changeFiles = diffTree(repository, patchInfo.getStartVersion(), patchInfo.getEndVersion());
		for (String changeFile : changeFiles) {
			copyFileToPatchDir(changeFile, projectInfo, patchInfo);
		}
		File zipFile = ZipUtil.zip(patchInfo.getPatchFileDir());
		LOG.info("生成补丁包:{}", zipFile.getPath());
	}
	
	public Set<String> diffTree(Repository repository, String startVersion, String endVersion)
			throws RevisionSyntaxException, AmbiguousObjectException, IncorrectObjectTypeException, IOException,
			GitAPIException {
		
		ObjectReader reader = repository.newObjectReader();
		CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
		Git git = new Git(repository);
		ObjectId old = repository.resolve(startVersion + "^{tree}");
		ObjectId head = repository.resolve(endVersion + "^{tree}");
		oldTreeIter.reset(reader, old);
		CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
		newTreeIter.reset(reader, head);
		List<DiffEntry> diffs = git.diff().setNewTree(newTreeIter).setOldTree(oldTreeIter).call();
		Set<String> changeFiles = new HashSet<>();
		for (DiffEntry diffEntry : diffs) {
			ChangeType changeType = diffEntry.getChangeType();
			LOG.info("old:{},oper:{},new:{}", diffEntry.getOldPath(), changeType.name(), diffEntry.getNewPath());
			if (!changeType.equals(ChangeType.DELETE)) {
				changeFiles.add(diffEntry.getNewPath());
			}
		}
		return changeFiles;
		
	}
	
}
